/**
 * 
 */
package simulation;

import java.util.ArrayList;
import java.util.Random;

/**
 * @author vladimir
 */
public class Interval_discrete {
	double B = -1;
	public int[] sites;
	int N = -1;
	Random rand = new Random();
	public double LD;
	public double epsilon;
	double prob;
	int maxRange = 0;

	public Interval_discrete(double B, double T, int N, double epsilon,
			double LD) {
		this.B = B;
		this.N = N;
		this.sites = new int[this.N];
		this.epsilon = epsilon;
		this.LD = LD;
		this.prob = 1 - Math.exp(-2 * this.LD);
		// System.out.println("Probability : " + this.prob);
		genInitialValues();
	}

	// generates initial cuts
	public void genInitialValues() {
		for (int z = 0; z < this.N; z++) {
			int newValue = 2 * rand.nextInt(2) - 1;
			this.sites[z] = newValue;
		}
	}

	/*
	 * returns List with clusters that we will try to flip
	 */
	public ArrayList<Integer> newCluster() {
		int seed = rand.nextInt(this.N);
		return newCluster(seed);
		// ArrayList<Integer> result = new ArrayList<Integer>();
		// result.add(seed);
		// return result;
	}

	public ArrayList<Integer> newCluster(int seed) {
		ArrayList<Integer> result = new ArrayList<Integer>();
		result.add(seed);
		return result;
		// int spinValue = this.sites[seed];
		// this.sites[seed] *= -1;
		// // going up
		//
		// for (int z = seed + 1; z < seed + this.maxRange; z++) {
		// int tz = z;
		// if (tz >= this.N) {
		// tz -= this.N;
		// }
		// if (this.sites[tz] == spinValue) {
		// if (rand.nextFloat() < this.prob) {
		// result.add(tz);
		// this.sites[tz] *= -1;
		// continue;
		// }
		// }
		// break;
		// }
		// // going down
		// for (int z = seed - 1; z > seed - this.maxRange; z--) {
		// int tz = z;
		// if (tz < 0) {
		// tz += this.N;
		// }
		// if (this.sites[tz] == spinValue) {
		// if (rand.nextFloat() < this.prob) {
		// result.add(tz);
		// this.sites[tz] *= -1;
		// continue;
		// }
		// }
		// break;
		// }
		// // flip everything back;
		// for (Integer z : result) {
		// this.sites[z] *= -1;
		// if (this.sites[z] != spinValue) {
		// System.err.println("!!!!");
		// System.exit(0);
		// }
		// }
		// if (result.size() > 2 * this.maxRange + 1) {
		// System.err.println("our cluster is too big");
		// System.exit(0);
		// }
		// return result;
	}

	/*
	 * returns value on the interval if no arguments returns whole value if
	 * there is cluster in arguments - will return value of the cluster
	 */
	public int value() {
		int result = 0;
		for (int z = 0; z < this.sites.length; z++) {
			result += this.sites[z];
		}
		return result;
	}

	public int value(ArrayList<Integer> cluster) {
		int result = 0;
		for (Integer site : cluster) {
			if ((site < 0) || (site >= this.N)) {
				System.err.println("In value\n site : " + site + "\n this.N : "
						+ this.N);
				System.exit(0);
			}
			// System.out.println("site : " + site);
			// System.out.println("siteValue : " + this.sites[site]);
			result += this.sites[site];
		}
		return result;
	}

	/*
	 * changes cluster to a new value x - lower value for new cluster y - upper
	 * value for new cluster z - index
	 */
	public void set(ArrayList<Integer> newCluster) {
		for (Integer site : newCluster) {
			this.sites[site] *= -1;
		}
	}

	/*
	 * prints all intervals with index, beginning, end, value
	 */
	public void print() {
		for (Integer siteValue : this.sites) {
			System.out.println(siteValue);
		}
	}

	/*
	 * Calculates Energy related to the magnetic field
	 */
	public double Energy_B() {
		if (this.B == 0) {
			return 0;
		} else {
			double result = Math.exp(-2 * this.LD * this.sites[this.N - 1]
					* this.sites[0]);
			for (int z = 0; z < this.N - 1; z++) {
				result -= Math.exp(-2 * this.LD * this.sites[z]
						* this.sites[z + 1]);
			}
			return this.B * result;
		}
	}

	/*
	 * Calculates change in Energy in temporal direction when we flip cluster
	 */
	public double DeltaE_B(ArrayList<Integer> cluster) {
		if (cluster.size() == this.sites.length) {
			return 0;
		}
		int min = cluster.get(0);
		int max = cluster.get(0);

		for (Integer site : cluster) {
			if (site < min) {
				min = site;
			} else if (site > max) {
				max = site;
			}
		}
		if (cluster.size() == 1) {
			if (min != max) {
				System.err
						.println("if cluster == onlu one site min should be equal to max and equal to this site \n"
								+ "min : "
								+ min
								+ "\n max : "
								+ max
								+ "\n site :" + cluster.get(0));
			}
		}

		int nextMin = min - 1;
		if (nextMin == -1) {
			nextMin = this.sites.length - 1;
		}
		int nextMax = max + 1;
		if (nextMax == this.sites.length) {
			nextMax = 0;
		}
		if (this.sites[min] != this.sites[max]) {
			System.err.println("should be same value on the cluster");
			System.exit(0);
		}
		return this.LD
				* (this.sites[min] * this.sites[nextMin] + this.sites[max]
						* this.sites[nextMax]);
	}
}
